/* Bfgeshka, 2021
 * Made for version 3.3.2 */

var Utils = import Custom/BUtils.stone
var Stats = import Custom/Stats.stone

/* Config */
var offTop = 1
var keyToggle = back
var bgW = 15
var gradientBg = true

var boxbg = #101010
var colMisc = #444444
var colName = #666666
var colLoc = #FF8CF8
var colHealth = #00B117
var colArmor = #255BC3
var colBuff = #357F00
var colDebuff = #BB000D
var colFoe = #00AD98
var colHpGood = #00B117
var colHpMid = #8F9400
var colHpBad = #BB000D
var colArGood = #255BC3
var colArBad = #666666
var colLocStars = #white
var colLoopCur = #white
var colLoopOld = #666666
var colLoopPrmt = #777777
var colCooldown = #9A3FCE
var colWeakness = #aa0000

var visible = true
var iTogD = false
var iTogU = false
var storageKvis = "bui_visible"

var armorf = 1.0
var maxarmorf = 1.0

//var lastlooptime = -1
//var lastlooptime2 = -1

var foeTimeLast = 0
//var foeStateLast = 0
//var foeStateCur = 0
//var foeStateFrames = 0
var hpLast = maxhp

var dFTime = []
var dFDamage = []
var dFState = []
var dFFrame = []
var dFFoeTime = []

var locScreens = -1
var lastScreenI = -1

func SaveDmgFrame ()
	dFTime.Add(string.Format( "{0}", Stats.frame ))
	dFDamage.Add(string.Format( "{0}hp", hpLast - hp ))
	dFState.Add(string.Format( "s{0}", Stats.foeStateCur ))
	dFFrame.Add(string.Format( "f{0}", Stats.foeStateFrames))
	dFFoeTime.Add(string.Format( "ft{0}", foeTimeLast))
	return

func FoeFrames ()
	? hp < hpLast
		SaveDmgFrame()
	hpLast = hp
//	foeStateLast = foeStateCur
	foeTimeLast = foe.time

func ProcessInputs ()
	? key = keyToggle
		iTogD = true
	? iTogD & key ! keyToggle
		iTogU = true
	? iTogD & iTogU
		visible = !visible
		>
		iTogD = false
		iTogU = false
		storage.Set( storageKvis, visible )

func OnBegin ()
	colLocStars = Utils.ColByLvl(loc.stars)
	visible = storage.Get( storageKvis, true )

func OnLoop ()
//	loopcount++
//	lastlooptime2 = lastlooptime
//	lastlooptime = Stats.frame
//	looptime = 0
	foeTimeLast = 0
	dFDamage.Clear()
	dFState.Clear()
	dFFrame.Clear()
	dFTime.Clear()
	hpLast = hp

func DrawHpBar ( iX, iY, w, glyphL, glyphR )
	var hpBarSym = 1.0 * maxhp / ( w - 2 )
	? hp > 2 * maxhp / 3.0
		colHealth = colHpGood
	:? hp > maxhp / 3.0
		colHealth = colHpMid
	:
		colHealth = colHpBad

	var hpBar = ""
	hpBar = glyphL
	for i = 1..( w - 2 )
		? hpBarSym * i <= hp
			hpBar = hpBar + "═"
		:? hpBarSym * ( i - 0.5 ) <= hp
			hpBar = hpBar + "~"
		:
			hpBar = hpBar + " "
	hpBar = hpBar + glyphR
	>`@iX@,@iY@,@colHealth@,@hpBar@

func DrawArBar ( iX, iY, w, glyphL, glyphR )
	var arBar = ""
	var armorf = armor + 0.1 * armor.f
	var maxarmorf = maxarmor * 1.0
	var arBarSym = maxarmorf / ( w - 2 )
	? armorf > 0
		colArmor = colArGood
	:
		colArmor = colArBad

	arBar = glyphL
	for i = 1..( w - 2 )
		? armorf > maxarmorf + 1 & i = ( w - 2 )
			arBar = arBar + "»"
		:? maxarmorf = 0 & armorf < 0.1
			arBar = arBar + "×"
		:? arBarSym * i <= armorf
			arBar = arBar + "═"
		:? arBarSym * ( i - 0.5 ) <= armorf
			arBar = arBar + "~"
		:
			arBar = arBar + " "
	arBar = arBar + glyphR
	>`@iX@,@iY@,@colArmor@,@arBar@

func DrawFoeBuffs ( iY )
	var arrd = []
	var arrb = []
	? foe.debuffs.count > 0
		arrd = Utils.GetBuffArr(foe.debuffs.string)
		for i = 0..arrd.Count() - 1
			>`@bgW + 1@,@iY - i@,@colDebuff@,@arrd[i]@
	? foe.buffs.count > 0
		arrb = Utils.GetBuffArr(foe.buffs.string)
		for i = 0..arrb.Count() - 1
			>`@bgW + 10@,@iY - i@,@colBuff@,@arrb[i]@

func DrawFoe ( offset )
	? !foe
		return

	var foeHp = ""
	var foeAr = ""
	var foeCount = ""
	var foeDist = ""
	var foeColHp = ""
	var foeColAr = ""
	var foeName = ""

	foeName = string.Format( "{0} ☆{1}", foe.name, foe.level )
	? foe = boss
		? foe = phase1
			foeName = foeName + " Ph 1"
		:? foe = phase2
			foeName = foeName + " Ph 2"
		:? foe = phase3
			foeName = foeName + " Ph 3"

	foeHp = string.Format( "{0}/{1}", foe.hp, foe.maxhp )
	foeAr = string.Format( "{0}/{1}", foe.armor, foe.maxarmor )
	? foe.count < 10
		foeCount = string.Format( "f∑: {0}", foe.count )
	:
		foeCount = string.Format( "f∑:{0}", foe.count )
	foeDist = string.Format( "→: {0}", foe.distance )

	? foe.armor < 1
		foeColAr = colArBad
	:
		foeColAr = colArGood

	?  foe.hp < foe.maxhp / 3
		foeColHp = colHpBad
	:? foe.hp < 2 * foe.maxhp / 3
		foeColHp = colHpMid
	:
		foeColHp = colHpGood

	var weak = Utils.BU_foeWeak()
	>`@bgW + 1@,@offset@,@Utils.ColByLvl(foe.level)@,@foeName@
	>`@bgW + string.Size(foeName) + 2@,@offset@,@colWeakness@,@weak@
	>`@bgW - string.Size(foeCount)@,@offset@,@colLoc@,@foeCount@
	>`@0@,@offset@,@colName@,@foeDist@
	>`@0@,@offset - 2@,@colHpGood@,HP
	>`@bgW - string.Size(foeHp)@,@offset - 2@,@foeColHp@,@foeHp@
	>`@0@,@offset - 1@,@colArGood@,AP
	>`@bgW - string.Size(foeAr)@,@offset - 1@,@foeColAr@,@foeAr@

	? foe.debuffs.count + foe.buffs.count > 0
		DrawFoeBuffs( offset - 2 )

	>`@bgW + 1@,@offset - 1@,@colMisc@,Foe state @foe.state@ (@foe.time@fr)

func DrawBgVert ( grad, xoffset, yoffset, width, height )
	? !grad
		draw.Bg( xoffset, yoffset, boxbg, width, height )
		return

	var grayLowest = 0   /* lowest channel value, on cos() = 0 */
	var grayHighest = 15 /* highest channel value, on cos() = .5 */
	var cosPow = 4       /* more gradient on sides, default 1 */
	var mid = height / 2.0 - 0.5
	var grayStr = ""
	var grayInt = 0
	var cosRes = 0
	for i = 0..height
		cosRes = 1 - math.Abs(math.Pow( math.Cos( ( i - mid ) / mid ), cosPow ))
		grayInt = math.Round( 2 * ( grayHighest - grayLowest ) * cosRes + grayLowest )
		? ( grayInt < 10 )
			grayStr = string.Format( "0{0}", grayInt )
		:
			grayStr = string.Format( "{0}", grayInt )
		draw.Bg( xoffset, i + yoffset, string.Format( "#{0}{0}{0}", grayStr), width, 1 )

func DrawLoops ( offset )
	? Stats.prevLoops.Count() > 0
		>`@bgW / 2 + 1 @,@offset + 2@,@colLoopPrmt@,σ←
		>`@bgW - Utils.BU_numsyml(Stats.prevLoops[0])@,@offset + 2@,@colLoopOld@,@Stats.prevLoops[0]@
		? Stats.loops > 1
			>`@0@,@offset + 2@,@colLoopPrmt@,←←
			>`@bgW / 2 - Utils.BU_numsyml(Stats.prevLoops[1])@,@offset + 2@,@colLoopOld@,@Stats.prevLoops[1]@
	>`@bgW / 2 + 1@,@offset + 3@,@colLoopPrmt@,σ▶
	>`@bgW - Utils.BU_numsyml(Stats.frame)@,@offset + 3@,@colLoopCur@,@Stats.frame@
	>`@bgW / 2 + 1@,@offset + 4@,@colLoopPrmt@,σ≈
	>`@bgW - Utils.BU_numsyml(loc.averageTime)@,@offset + 4@,@colLoopOld@,@loc.averageTime@
	>`@0@,@offset + 4@,@colLoopPrmt@,σα
	>`@bgW / 2 - Utils.BU_numsyml(loc.bestTime)@,@offset + 4@,@colLoopOld@,@loc.bestTime@
	>`@0@,@offset + 3@,@colLoopPrmt@,σΣ
	>`@bgW / 2 - Utils.BU_numsyml(Stats.loops)@,@offset + 3@,@colLoopOld@,@Stats.prevLoops.Count()@

func DrawItems ( offset )
	var itemleft = ""
	var itemright = ""

	? item.left
		itemleft = Utils.GetItemName(item.left)
	:
		itemleft = "---"
	>`@Utils.BU_offsetMiddle( itemleft, bgW )@,@offset@,@colName@,@itemleft@
	? item.right
		itemright = Utils.GetItemName(item.right)
	:
		itemright = "---"
	>`@Utils.BU_offsetMiddle( itemright, bgW )@,@offset + 1@,@colName@,@itemright@

func DrawDebuffs ( offsetX, offsetY )
	var arr = []
	? debuffs.count > 0
		arr = Utils.GetBuffArr(debuffs.string)
		for i = 0..arr.Count() - 1
			>`@offsetX@,@offsetY + i@,@colDebuff@,@arr[i]@

func DrawBuffs ( offsetX, offsetY )
	var arr = []
	? buffs.count > 0
		arr = Utils.GetBuffArr(buffs.string)
		for i = 0..arr.Count() - 1
			>`@offsetX@,@offsetY + i@,@colBuff@,@arr[i]@

func DrawItemCooldown ( sItem, sItemName, col, iW, iX, iY )
	? item.GetCount(sItem) = 0
		return false

	var coolText = string.Format("{0}", item.GetCooldown(sItem) / 30)
	? item.GetCooldown(sItem) < 1
		coolText = "Rdy"
	>`@iX@,@iY@,@colMisc@,@sItemName@:
	>`@iX + Utils.BU_offsetRight( coolText, iW )@,@iY@,@col@,@coolText@
	return true

func DrawPlayerData ( col, offY )
	var gpText = string.Format( "GP: {0}", totalgp )
	>`@screen.w - string.Size(player.name)@,@offY@,@col@,@player.name@
	>`@screen.w - string.Size(gpText)@,@offY + 1@,@col@,@gpText@

func DrawHpValue ( iX, iY, w )
	var hpText = string.Format( "{0}/{1}", hp, maxhp )
	>`@iX@,@iY@,@colHealth@,HP
	>`@iX + Utils.BU_offsetRight( hpText, w )@,@iY@,@colHealth@,@hpText@

func DrawArValue ( iX, iY, w )
	var armorf = armor + 0.1 * armor.f
	? armorf < 0
		armorf = 0
	var maxarmorf = maxarmor * 1.0
	var arText = string.Format( "{0}/{1}", armorf, maxarmorf )
	>`@iX@,@iY@,@colArmor@,AP
	>`@iX + Utils.BU_offsetRight( arText, bgW )@,@iY@,@colArmor@,@arText@

func DrawAI ( iX, iY, twolines )
	var colAiTrue = #white
	var colAiFalse = #777777
	var colE = colAiFalse
	var colP = colAiFalse
	var colW = colAiFalse
	var colI = colAiFalse
	? ai.enabled
		colE = colAiTrue
	? ai.paused
		colP = colAiTrue
	? ai.walking
		colW = colAiTrue
	? ai.idle
		colI = colAiTrue
	var sndpartX = iX + 2
	var sndpartY = iY
	? twolines
		sndpartX = iX
		sndpartY = iY + 1
	>`@iX@,@iY@,@colE@,E
	>`@iX + 1@,@iY@,@colP@,P
	>`@sndpartX@,@sndpartY@,@colW@,W
	>`@sndpartX + 1@,@sndpartY@,@colI@,I
	return

func DrawLocPosition ( iX, iY )
	? locScreens < 2
		>`@iX@,@iY@,@colMisc@,[@1@]

	var locdone = "[ "
	var loccur = ""
	var locnext = ""
	for i = 1..locScreens
		?  i < screen.i
			locdone = locdone + i + " "
		:? i = screen.i
			loccur = i + " "
		:
			locnext = locnext + i + " "

	>`@iX@,@iY@,@colMisc@,@locdone@
	>`@iX + string.Size(locdone)@,@iY@,@colLoc@,@loccur@
	>`@iX + string.Size(locdone) + string.Size(loccur)@,@iY@,@colMisc@,@locnext@]
	return

func DrawItemCooldowns ( iW, iX, iY )
	var dynOffsetTop = iY
	var semirows = 0
	? DrawItemCooldown( "quarterstaff", "Qsf", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "mind", "Mnd", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "dash", "Dsh", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "bash", "Bsh", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "bardiche", "Brd", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "blade", "Bld", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++
	? DrawItemCooldown( "skeleton_arm", "Arm", colCooldown, iW / 2, ( semirows % 2 ) * ( iW / 2 + 1 ), dynOffsetTop + semirows / 2 )
		semirows++

func DrawDmg ( iW, iH, iX, iY )
	? dFDamage.Count() = 0
		return
	var index0 = 0
	? dFDamage.Count() > iH
		index0 = dFDamage.Count() - iH
	>`@iX@,@iY@,Frm/Dmg/Stt/Tim
	var indexLine = 0
	var timeStr = ""
	var hpStr = ""
	var stateStr = ""
	var frameStr = ""
	for i = index0..dFDamage.Count() - 1
		indexLine++
		>`@iX@,@iY + indexLine@,@colMisc@,@dFTime[i]@
		>`@iX + string.Size(dFTime[i])@,@iY + indexLine@,@colHpBad@,@dFDamage[i]@
		>`@iX + string.Size(dFTime[i]) + string.Size(dFDamage[i])@,@iY + indexLine@,@colMisc@,@dFState[i]@@dFFrame[i]@
	return

func DrawShown ()
	disable loadout print
	disable hud

	var prm = "Press X to hide UI"

	DrawItemCooldowns( bgW, 0, 4 + offTop )

	DrawBgVert( gradientBg, 0, 0, bgW, screen.h )
	DrawAI( 5, offTop + 1, true )
	DrawHpValue( 0, offTop + 1, bgW )
	DrawHpBar( 0, offTop, bgW, "╔", "╗" )
	DrawArBar( 0, offTop + 3, bgW, "╚", "╝" )
	DrawArValue( 0, offTop + 2, bgW )
	DrawBuffs( bgW + 1, offTop + 1 )
	DrawDebuffs( bgW + 1 + 9, offTop + 1 )
	DrawItems( screen.h / 2 )
	DrawLoops( screen.h - 8 )
	DrawFoe( screen.h - 1 )
	DrawPlayerData( colName, offTop )

	>`@Utils.BU_offsetRight( prm, screen.w )@,@screen.h - 1@,@colMisc@,@prm@
	>`@bgW + 1@,@offTop@,@colLoc@,@loc.name@
	>`@bgW + string.Size(loc.name) + 2@,@offTop@,@colLocStars@,☆@loc.stars@
	DrawLocPosition( bgW + string.Size(loc.name) + 4 + string.Size(string.Format("{0}", loc.stars)), offTop )
	DrawDmg( 17, 10, screen.w - 17, 4 )

func RefreshScreenI ()
	var PrefKey = string.Format("{0}:{1}", loc.id, loc.stars)
	? storage.Get( PrefKey, -1 ) < screen.i
		storage.Set( PrefKey, screen.i )
	lastScreenI = screen.i
	locScreens = storage.Get( string.Format( "{0}:{1}", loc.id, loc.stars ), 1 )

func DrawHidden ()
	enable loadout print
	enable hud
	var prm = "Press X to show UI"
	>`@Utils.BU_offsetRight( prm, screen.w )@,@1@,@colMisc@,@prm@

func Update ()
//	looptime++
	? loc.begin
		OnBegin()
	? loc.loop
		OnLoop()
	FoeFrames()
	Stats.OnUpdate()
	? lastScreenI ! screen.i
		RefreshScreenI()
	ProcessInputs()
	? visible
		DrawShown()
	:
		DrawHidden()

Update()

//var lastpick = ""
//? pickup
//        lastpick = pickup
//        >`@10@,@10@,@lastpick@

// Common Treasure
// tid_treasure_GT
// tid_treasure_OT
// tid_treasure_DT
